package com.atguigu.daijia.dispatch.service.impl;


import com.alibaba.fastjson.JSONObject;
import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.dispatch.mapper.OrderJobMapper;
import com.atguigu.daijia.dispatch.service.NewOrderService;
import com.atguigu.daijia.dispatch.xxl.client.XxlJobClient;
import com.atguigu.daijia.map.client.LocationFeignClient;
import com.atguigu.daijia.model.entity.dispatch.OrderJob;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.map.SearchNearByDriverForm;
import com.atguigu.daijia.model.vo.dispatch.NewOrderTaskVo;
import com.atguigu.daijia.model.vo.map.NearByDriverVo;
import com.atguigu.daijia.model.vo.order.NewOrderDataVo;
import com.atguigu.daijia.order.client.OrderInfoFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {

    @Autowired
    private OrderJobMapper orderJobMapper;

    @Autowired
    private XxlJobClient xxlJobClient;
    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;
    @Autowired
    private LocationFeignClient locationFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;


    //添加并开始新订单任务调度，返回任务的ID
    @Override
    public Long addAndStartTask(NewOrderTaskVo newOrderTaskVo) {
        //判断当前订单是否启动了任务调度（通过查询order_job表）
        LambdaQueryWrapper<OrderJob> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderJob::getOrderId,newOrderTaskVo.getOrderId());

        OrderJob orderJob = orderJobMapper.selectOne(wrapper);
        //为空则代表未开启-->则启动
        if (orderJob==null){
            //返回任务ID
            Long jobId = xxlJobClient.addAndStart(
                    "newOrderTaskHandler", //执行的具体任务job方法
                    "",
                    "0 0/1 * * * ?", //执行时间(每分钟执行一次)
                    "新订单任务,订单id："+newOrderTaskVo.getOrderId()//描述
            );
            //记录订单与任务的关联信息到order_job表
            orderJob = new OrderJob();
            orderJob.setOrderId(newOrderTaskVo.getOrderId());//订单id
            orderJob.setJobId(jobId);//任务id
            orderJob.setParameter(JSONObject.toJSONString(newOrderTaskVo));//
            orderJobMapper.insert(orderJob);
        }
        //返回任务ID
        return orderJob.getJobId();
    }

    //执行任务：搜索附近代驾司机
    @Override
    public void executeTask(long jobId) {
        //1.判断任务是否已经创建，没有就结束
        LambdaQueryWrapper<OrderJob> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(OrderJob::getJobId,jobId);
        OrderJob orderJob = orderJobMapper.selectOne(wrapper);
        if (orderJob==null){
            return;
        }
        //2.任务已经创建，查询订单状态
        Integer status = orderInfoFeignClient.getOrderStatus(orderJob.getOrderId()).getData();
        //不是等待接单的状态直接结束任务（可能司机已经接单了，或者取消了订单）
        if (status != 1){
            xxlJobClient.stopJob(jobId);
            return;
        }
        //解析出newOrderTaskVo
        NewOrderTaskVo newOrderTaskVo = JSONObject.parseObject(orderJob.getParameter(), NewOrderTaskVo.class);

        //3.远程调用，搜索附近的司机，返回司机列表
        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        searchNearByDriverForm.setLongitude(newOrderTaskVo.getStartPointLongitude());//经度
        searchNearByDriverForm.setLatitude(newOrderTaskVo.getStartPointLatitude());//纬度
        searchNearByDriverForm.setMileageDistance(newOrderTaskVo.getExpectDistance());//预估里程（用于筛选司机）
        List<NearByDriverVo> driverVos= locationFeignClient.searchNearByDriver(searchNearByDriverForm).getData();

        //4.遍历司机，得到每个司机，然后给每个司机创建临时队列，存储订单信息
        for (NearByDriverVo driverVo : driverVos) {
            String repeatKey = "driver:order:repeat:list:"+newOrderTaskVo.getOrderId();
            //使用set集合避免重复推送
            Boolean b = redisTemplate.opsForSet().isMember(repeatKey, driverVo.getDriverId());
            if (!b){
                //加入到set集合中，表示当前订单已经推送给该司机了
                redisTemplate.opsForSet().add(repeatKey, driverVo.getDriverId());
                //设置订单的过期时间为15分钟
                redisTemplate.expire(repeatKey, 15, TimeUnit.MINUTES);

                NewOrderDataVo newOrderDataVo = new NewOrderDataVo();
                newOrderDataVo.setOrderId(newOrderTaskVo.getOrderId());
                newOrderDataVo.setStartLocation(newOrderTaskVo.getStartLocation());
                newOrderDataVo.setEndLocation(newOrderTaskVo.getEndLocation());
                newOrderDataVo.setExpectAmount(newOrderTaskVo.getExpectAmount());
                newOrderDataVo.setExpectDistance(newOrderTaskVo.getExpectDistance());
                newOrderDataVo.setExpectTime(newOrderTaskVo.getExpectTime());
                newOrderDataVo.setFavourFee(newOrderTaskVo.getFavourFee());
                newOrderDataVo.setDistance(driverVo.getDistance());
                newOrderDataVo.setCreateTime(newOrderTaskVo.getCreateTime());
                //将消息保存到司机的临时队列里面，司机接单了会定时轮询到他的临时队列获取订单消息
                String key = "driver:order:temp:list:"+driverVo.getDriverId();
                redisTemplate.opsForList().leftPush(key, JSONObject.toJSONString(newOrderDataVo));
                //设置过期时间--1分钟未消费则过期
                redisTemplate.expire(key, 1, TimeUnit.MINUTES);
            }
            
        }
    }

    //从队列查询司机新订单数据
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        //存储司机队列中的订单数据
        ArrayList<NewOrderDataVo> list = new ArrayList<>();
        String key = "driver:order:temp:list:"+driverId;
        //查询队列的大小，判断是否有订单
        Long size = redisTemplate.opsForList().size(key);
        if (size>0){
            for (int i = 0; i < size; i++) {
                //获取队列中的数据
                String content = (String) redisTemplate.opsForList().leftPop(key);
                NewOrderDataVo newOrderDataVo = JSONObject.parseObject(content, NewOrderDataVo.class);
                list.add(newOrderDataVo);
            }
        }
        return list;
    }

    //清空司机新订单队列数据
    @Override
    public Boolean clearNewOrderQueueData(Long driverId) {
        String key = "driver:order:temp:list:"+driverId;
        redisTemplate.delete(key);
        return true;
    }
}
